#if UNITY_EDITOR && DEBUG_BEHAVIOUR_TREE
#define DEBUG_TREE
#endif
using GameToolkit.BehaviourTree;
using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine.UIElements;

namespace GameToolkit.Editor
{
    //public partial class BehaviourTreeGraph
    //{

    internal class DecoratorTitle : Label
#if DEBUG_TREE
        , IRuntimeBinding
#endif
    {
        internal readonly static string[] STAT_CLASS = { null, "condition-update", "condition-true", "condition-false" };
        ExecutableNodeVisual treeNode;
        Composite _inst;
#if DEBUG_TREE
        Decoration _runtimeInstance;
        ExecutableEntry runtimeNode;
        internal Decoration runtimeInstance => _runtimeInstance;
#else
        internal Decoration runtimeInstance => null;
#endif
        int mState;

        internal Port conditionPort;

        internal Composite composite
        {
            get { return _inst; }
            set
            {
                if (_inst != value)
                {
                    _inst = value;
                    if (_inst is ConditionReference cref)
                    {
                        if (conditionPort == null)
                        {
                            conditionPort = treeNode.InstantiatePort(Orientation.Horizontal, Direction.Input, Port.Capacity.Single, typeof(NodeState));
                            conditionPort.portColor = LogicNodeVisual.INPUT_COLOR;
                            conditionPort.portName = "";
                            conditionPort.style.position = Position.Relative;
                            conditionPort.style.left = -18;
                            conditionPort.style.top = -2;
                            conditionPort.style.width = 40;
                            conditionPort.style.height = 20;
                            this.Add(conditionPort);
                        }
                    }
                    else if (conditionPort != null)
                    {
                        var graph = GetFirstAncestorOfType<GraphView>();
                        var lst = new List<Edge>();
                        foreach (var edge in conditionPort.connections)
                        {
                            lst.Add(edge);
                        }
                        foreach (var edge in lst)
                        {
                            graph.RemoveElement(edge);
                        }
                        //conditionPort.DisconnectAll();
                        Remove(conditionPort);
                        conditionPort = null;
                    }
                }
                text = _inst == null ? "<none>" : BehaviourTreeLib.Instance.GetDescription(_inst);
            }
        }


        public DecoratorTitle(ExecutableNodeVisual node) : base()
        {
            this.treeNode = node;
            AddToClassList("node-decorator");
            UpdateState();
        }

#if DEBUG_TREE

        public void BindRuntime(BehaviourTreePlayer player)
        {
            var inst = _inst == null ? null : player.GetInstanceByGuid(_inst.guid) as Decoration;
            if (inst != _runtimeInstance)
            {
                if (runtimeNode != null)
                    runtimeNode.OnStateChanged -= UpdateState;
                if (_runtimeInstance != null)
                    _runtimeInstance.OnStateChanged -= UpdateState;
                _runtimeInstance = inst;
                runtimeNode = treeNode.RuntimeInstance;
                if (_runtimeInstance != null)
                    _runtimeInstance.OnStateChanged += UpdateState;
                if (runtimeNode != null)
                    runtimeNode.OnStateChanged += UpdateState;
                UpdateState();
            }
        }

        public void UnbindRuntime()
        {
            if (runtimeNode != null)
            {
                runtimeNode.OnStateChanged -= UpdateState;
                runtimeNode = null;
            }
            if (_runtimeInstance != null)
            {
                _runtimeInstance.OnStateChanged -= UpdateState;
                _runtimeInstance = null;
                UpdateState();
            }
        }
#endif

        internal void UpdateState()
        {
            int stat;

#if DEBUG_TREE
            if (_runtimeInstance != null)
            {
                if (_runtimeInstance is IExecutableUpdateCallback && _runtimeInstance.attachedPlayer != null && _runtimeInstance.attachedPlayer.IsActiveNode(_runtimeInstance))
                    stat = (int)NodeState.Running;
                else if (!_runtimeInstance.IsStateObsolute && (_runtimeInstance.State == NodeState.Success || _runtimeInstance.State == NodeState.Failed))
                    stat = (int)_runtimeInstance.State;
                else
                    stat = (int)NodeState.Inactive;
            }
            else
#endif
            {
                stat = 0;
            }
            if (stat != mState)
            {
                var cname = STAT_CLASS[mState];
                if (!string.IsNullOrEmpty(cname))
                    RemoveFromClassList(cname);
                mState = stat;
                cname = STAT_CLASS[mState];
                if (!string.IsNullOrEmpty(cname))
                    AddToClassList(cname);
            }
        }

    }
    //}

}
